package cn.dengta.webapp.trade.service;

import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Resource;

import cn.dengta.common.context.I18N;
import cn.dengta.common.model.Messager;
import cn.dengta.common.model.TimeInterval;
import cn.dengta.common.web.Page;
import cn.dengta.context.model.UserI18nKey;
import cn.dengta.webapp.base.service.BaseServiceImpl;
import cn.dengta.webapp.trade.dao.AgentDao;
import cn.dengta.webapp.trade.dto.UserAgentDTO;
import cn.dengta.webapp.trade.dto.UserIntegralLogSumDTO;
import cn.dengta.webapp.trade.entity.Agent;
import cn.dengta.webapp.trade.model.Flow;
import cn.dengta.webapp.trade.model.TradeType;
import cn.dengta.webapp.user.entity.User;
import cn.dengta.webapp.user.form.query.UserQuery;
import cn.dengta.webapp.user.vo.AgentIncomeInfoVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import me.codeplayer.util.*;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;

import static cn.dengta.webapp.base.entity.BaseEntity.ID;
import static cn.dengta.webapp.base.entity.BizEntity.STATUS;
import static cn.dengta.webapp.trade.entity.Agent.*;

@Service
public class AgentService extends BaseServiceImpl<Agent, AgentDao, Long> {

	public static final Pair<Long, Long> EMPTY_AGENT = Pair.of(null, null);

	@Resource
	UserIntegralLogService userIntegralLogService;

	/**
	 * 根据 邀请码 查询对应的代理商
	 */
	public Agent getByInviteCode(String inviteCode) {
		return baseDao.selectOne(new QueryWrapper<Agent>().eq(INVITE_CODE, inviteCode));
	}

	public long getCountByInviteCode(String inviteCode) {
		return baseDao.selectCount(new QueryWrapper<Agent>().eq(INVITE_CODE, inviteCode));
	}

	public Agent get(@Nonnull User user) {
		return user.getType().isAgent() ? getByUserId(user.getId()) : get(user.getAgentId());
	}

	public Agent getByUserId(Long userId) {
		return super.getByUserId(userId);
	}

	public Agent getValid(Long id) {
		return baseDao.selectOne(new QueryWrapper<Agent>().eq(ID, id).ge(STATUS, Agent.AgentStatus.VALID.value));
	}

	/**
	 * 获取二级推广员成员列表
	 */
	public Page<UserAgentDTO> findSecondPage(Page<Agent> page, UserQuery query, TimeInterval agentJoinTimeInterval, TradeType... tradeTypes) {
		return baseDao.findSecondPage(page, query, agentJoinTimeInterval, tradeTypes);
	}

	/**
	 * 获取二级推广员成员列表 V2
	 */
	public Page<UserAgentDTO> findSecondPageV2(Page<Agent> page, UserQuery query, TimeInterval agentJoinTimeInterval, TradeType... tradeTypes) {
		return  baseDao.findSecondPageV2(page, query, agentJoinTimeInterval, tradeTypes);
	}

	/**
	 * 根据推广员ID查询一级与二级推广员ID 【Pair<oneId, twoId>】
	 */
	public Pair<Long, Long> getAgentPair(Long id) {
		if (X.isValid(id)) {
			final Agent agent = get(id);
			if (agent != null) {
				if (agent.isOne()) {
					return Pair.of(agent.getId(), null);
				}
				return Pair.of(agent.getParentId(), agent.getId());
			}
		}
		return EMPTY_AGENT;
	}

	public Pair<Long, Long> getAgentUserIdPair(Long id) {
		if (X.isValid(id)) {
			final Agent agent = get(id);
			if (agent != null) {
				if (agent.isOne()) {
					return Pair.of(agent.getUserId(), null);
				}
				final Agent oneAgent = get(agent.getParentId());
				return Pair.of(oneAgent.getUserId(), agent.getUserId());
			}
		}
		return EMPTY_AGENT;
	}

	public List<Agent> findByParentId(Long parentId) {
		QueryWrapper<Agent> wrapper = new QueryWrapper<>();
		wrapper.eq(PARENT_ID, parentId);
		return baseDao.selectList(wrapper);
	}

	public Messager<AgentIncomeInfoVO> userExtractIncome(User sessionUser, Agent agent) {
		if (agent == null) {
			agent = getByUserId(sessionUser.getId());
		}
		final boolean isOuter = agent.isOuter();
		final Long[] userIds = isOuter ? null : new Long[] { sessionUser.getId() };
		final Long[] agentIds = { agent.getId() };
		final TradeType tradeType = isOuter ? TradeType.INTEGRAL_GAIN : TradeType.INTEGRAL_GAIN_EXTRACT_USER;
		AgentIncomeInfoVO vo = new AgentIncomeInfoVO();
		EasyDate d = new EasyDate();
		Date begin = d.beginOf(Calendar.DAY_OF_MONTH).toDate();
		TimeInterval addTimeInterval = new TimeInterval(begin, d.endOf(Calendar.DAY_OF_MONTH).toDate(), -1, -1);
		final Integer incomeValue = Flow.INCOME.getValue();
		Integer level = agent.getLevel().getValue();
		List<UserIntegralLogSumDTO> todayLogDTOs = userIntegralLogService.findSumOfAgentInfo(agentIds, userIds, incomeValue, addTimeInterval, null, null, true, level, tradeType);
		addTimeInterval.setEnd(d.addDay(-1).toDate());
		addTimeInterval.setBegin(d.beginOf(Calendar.DAY_OF_MONTH).toDate());
		List<UserIntegralLogSumDTO> yesterdayLogDTOs = userIntegralLogService.findSumOfAgentInfo(agentIds, userIds, incomeValue, addTimeInterval, null, null, true, level, tradeType);
		addTimeInterval.setBegin(d.setDate(begin).beginOf(Calendar.MONTH).toDate());
		addTimeInterval.setEnd(d.endOf(Calendar.MONTH).toDate());
		List<UserIntegralLogSumDTO> monthLogDTOs = userIntegralLogService.findSumOfAgentInfo(agentIds, userIds, incomeValue, addTimeInterval, null, null, true, level, tradeType);
		d.setDate(begin);
		addTimeInterval.setBegin(d.addDay(-d.getWeekDay()).toDate()); // 周期周日-周六
		addTimeInterval.setEnd(d.addDay(6).endOf(Calendar.DAY_OF_MONTH).toDate());
		List<UserIntegralLogSumDTO> weekLogDTOs = userIntegralLogService.findSumOfAgentInfo(agentIds, userIds, incomeValue, addTimeInterval, null, null, true, level, tradeType);
		X.use(todayLogDTOs, X::isValid, c -> vo.setTodayTradeAmount(c.get(0).getTotalTradeAmount()));
		X.use(yesterdayLogDTOs, X::isValid, c -> vo.setYesterdayTradeAmount(c.get(0).getTotalTradeAmount()));
		X.use(weekLogDTOs, X::isValid, c -> vo.setWeekTradeAmount(c.get(0).getTotalTradeAmount()));
		X.use(monthLogDTOs, X::isValid, c -> vo.setMonthTradeAmount(c.get(0).getTotalTradeAmount()));
		d.setDate(begin);
		final Date date = d.addDay(-1).toDate();// 昨日
		addTimeInterval.setBegin(date);
		addTimeInterval.setEnd(date);
		List<UserIntegralLogSumDTO> yesterday = userIntegralLogService.findSumOfAgentInfo(agentIds, userIds, incomeValue, addTimeInterval, null, null, true, level, tradeType);
		X.use(yesterday, X::isValid, c -> vo.setTotalTradeAmount(c.get(0).getTotalTradeAmount()));
		vo.setAgentTotalTradeAmount(userIntegralLogService.sumAgentTotal(agent.getId()));
		vo.initTradeAmount(vo);
		return Messager.exposeData(vo);
	}

	public Messager<Agent> updateUserRate(Agent agent, Integer userRate) {
		Assert.isTrue(agent != null && agent.isInner());
		I18N.assertTrue(userRate != null && userRate >= 0 && userRate <= 100, UserI18nKey.AGENT_USER_RATE_OUT_OF_BOUNDS);
		int update = baseDao.updateUserRate(agent.getId(), userRate);
		return update > 0 ? Messager.OK(I18N.msg(UserI18nKey.OPERATE_EDIT_SUCCESS)) : Messager.error(I18N.msg(UserI18nKey.OPERATE_FAIL));
	}

	public Map<Long, Long> findUserByAgentId(List<Long> ids) {
		if (X.isValid(ids)) {
			List<Agent> list = findByIds(ids);
			return list.stream().collect(Collectors.toMap(Agent::getId, Agent::getUserId));
		}
		return Collections.emptyMap();
	}

	public List<Agent> findAgentByUserIds(Collection<Long> userIds) {
		QueryWrapper<Agent> wrapper = new QueryWrapper<>();
		wrapper.in(USER_ID, userIds);
		return selectList(wrapper);
	}

}
